#include "EmisorDeFrames.h"
using std::endl;
using std::cerr;
using std::cout;

EmisorDeFrames::EmisorDeFrames(Socket *socket_av, bool *en_clase) {
	this->socket_av = socket_av;
	this->transmitir = *en_clase;
}

// Envia frames
void EmisorDeFrames::run() {
	char cod_op = '0';
	bool envio_ok;
	bool hilo_leave = false;
	AVFrame* cuadro_rgb = NULL;
	AVFrame* cuadro_yuv = NULL;
	uint8_t* buffer_cuadro_yuv = NULL;
	SwsContext* conversor = NULL;
	int size_yuv = 0;
	// Obtiene un puntero a la ventana (usa un puntero a drawable, ver mas adelante porque)
	Glib::RefPtr<Gdk::Drawable> ventana = Gdk::Window::get_default_root_window();
	// Obtiene ancho y alto de la ventana
	int width_ventana = 0, height_ventana = 0;
	ventana->get_size(width_ventana, height_ventana);
	// Calcula y guarda el ancho y alto de la ventana en el video
	int width_ventana_reducida = width_ventana / 4;
	int height_ventana_reducida = height_ventana / 4;
	CodificadorVideo *cod_video = new CodificadorVideo();
	cod_video->registrar_codecs();

	// Busca el codec
	cod_video->busca_encoder();

	cod_video->ini_contexto(width_ventana_reducida, height_ventana_reducida);

	// Abre el codec
	cod_video->abre_encoder();

	//-------------------------------Escritura del video frame-------------------------------//
	// Crea un swscontext para conversion de imagen
	conversor = sws_getContext(width_ventana, height_ventana, PIX_FMT_RGB24, // Fuente
			width_ventana_reducida, height_ventana_reducida, PIX_FMT_YUV420P, // Destino
			SWS_BILINEAR, NULL, NULL, NULL);

	// Crea un cuadro en RGB para guardar la informacion del pixbuf
	cuadro_rgb = avcodec_alloc_frame();

	// Crea un cuadro para convertir a yuv el frame en rgb
	cuadro_yuv = avcodec_alloc_frame();

	// Crea un buffer para escritura de video
	cod_video->ini_buffer(&cuadro_yuv, &buffer_cuadro_yuv, &size_yuv);

	while(transmitir) {
		gdk_threads_enter();
		hilo_leave = false;
		if(!(envio_ok = socket_av->enviar(&cod_op, sizeof(cod_op)))) {
			std::cerr << "No se pudo enviar el codigo" << std::endl;
			break;
		}

		// Declara un pixbuf que contendra el contenido de la ventana
		Glib::RefPtr<Gdk::Pixbuf> pixbuf= Gdk::Pixbuf::create(ventana, Gdk::Colormap::get_system(), 0, 0, width_ventana,
				height_ventana);
		// Dibuja en el pixbuf el contenido de la ventana
		ventana->draw_pixbuf(pixbuf, 0, 0, 0, 0, width_ventana, height_ventana,
				Gdk::RGB_DITHER_NORMAL, 0, 0);
		// Llena el cuadro_rgb con el contenido del pixbuf
		avpicture_fill((AVPicture*) cuadro_rgb, pixbuf->get_pixels(),
				PIX_FMT_RGB24, width_ventana, height_ventana);
		// El contenido del cuadro_rgb pasa al cuadro_yuv (escalado)
		sws_scale(conversor, cuadro_rgb->data, cuadro_rgb->linesize, 0,
				height_ventana, cuadro_yuv->data, cuadro_yuv->linesize);
		// Hace un encode de la imagen
		if(!cod_video->codificar(&cuadro_yuv, &buffer_cuadro_yuv, &size_yuv)) {
			cerr << "Error codificando" << endl;
			break;
		}

		if(!(socket_av->enviar(&size_yuv, sizeof(size_yuv)))) {
			cerr << "Error enviando tamanio del size" << endl;
			break;
		}
		if(!(socket_av->enviar(buffer_cuadro_yuv, size_yuv))) {
			cerr << "Error enviando el frame codificado" << endl;
			break;
		}
		gdk_threads_leave();
		hilo_leave = true;
		//sleep(1);
	}
	if(!hilo_leave)
		gdk_threads_leave();
	else {
		// Libera los cuadros
		av_free(cuadro_rgb);
		av_free(cuadro_yuv);
		// Libera el buffer del cuadro yuv
		av_free(buffer_cuadro_yuv);
		// Libera el swscontext
		av_free(conversor);
		// Libero el codificador
		delete (cod_video);
	}
}

void EmisorDeFrames::pararTransmision() {
	transmitir = false;
}

EmisorDeFrames::~EmisorDeFrames() {}
